<?php
namespace Api\Utils;

use Utuo\WechatAdvance;
use Utuo\WechatAdvance\QrCode;
use Utuo\DBRW;

class QrcodeUtil {
	
	public $errors = array(
		'001' => '未成功获得access_token',
	);
	
	public $errorCode = "";
	
	protected $config = null;
	
	protected $cid = 0;
	
	protected $uid = 0;
	
	protected $openId = 0;
	
	protected $qrKeyPrefix = "__qr_key_";
	
	protected $wechatAdvance = null;
	
	protected $enableCache = false; // 缓存二维码链接地址不正确
	
	/**
	 * 二维码图片内字段基础配置
	 * @var unknown
	 */
	public static $fieldsConfig = array(
		"qrcode" => array(
				"type" => 1,
				"id" => 'box',
				"w" => 100,
				"h" => 100,
				"dataType" => "Image"
		),
		"face" => array(
				"type" => 1,
				"id" => 'face',
				"w" => 48,
				"h" => 48,
				"dataType" => "Image"
		),
		"nickname" => array(
				"type" => 0,
				"id" => 'nickname',
				"title" => '昵称',
				"dataType" => "Text"
		),
	);
	
	/**
	 * 获得高级接口
	 * @return \Utuo\WechatAdvance
	 */
	public function getWechatAdvance() {
		return $this->wechatAdvance;
	}
	
	/**
	 * 设置字段的属性值 
	 */
	public function setFieldValue($fieldName, $attrName, $fieldValue) {
		$qrConfig = &$this->config['qrConfig']['fields'];
		if ( isset($qrConfig[$fieldName]) ) {
			$qrConfig[$fieldName][$attrName] = $fieldValue;
		}
	}
	
	/**
	 * 字段是否已设置
	 */
	public function fieldExist( $fieldName ) {
		$qrConfig = &$this->config['qrConfig']['fields'];
		if ( isset($qrConfig[$fieldName]) ) {
			return true;
		}
		return false;
	}
	
	/**
	 * 获得实例
	 * @param unknown $driver
	 * @param unknown $config
	 * @return \Utuo\Pay
	 */
	public final static function getInstance( $config = array() ) {
		static $instance;
		if(!$instance) $instance = new QrcodeUtil( $config );
		return $instance;
	}
	
	/**
	 * $config array(
	 * 	  'cid' => 0, //* 客户id
	 * 	  'modelName' => 'DistributionShop', //* 模块名称
	 * 	  'qrConfig' => array(array(2) {
	 * 				'fields' => array(
	 * 					'qrcode' => array(
	 * 					   ["img"] => string(72) "http://wmei-wmei5.stor.sinaapp.com/2015-01-23/2015012318131685222077.jpg"
	 * 					   ["rect"] => array(4) {
	 * 					     ["x"] => string(2) "96"
	 * 					     ["y"] => string(3) "151"
	 * 					     ["w"] => string(3) "202"
	 * 					     ["h"] => string(3) "202"
	 * 					   }
	 * 					),
	 * 				),
	 * 				"img" => "", // 背景图
	 * 	  }),  //* 二维码配置 ( cid 与 modelName 些项可以不设置 )
	 * 	  'wechatConfig' => array(), //* 微信配置  ( cid 与 modelName 些项可以不设置 )
	 * )
	 * @param unknown $config
	 */
	public function __construct( $config ) {
		$this->config = $config;
		$this->cid =  $config['cid'];
		$this->openId =  $config['openId'];
		$this->uid = M("WechatUser")->where(array('cid' => $this->cid, 'openId' => $this->openId))->getField('id')*1;
		$this->modelName = $config['modelName'];
		$wechatConfig = null;
		$qrConfig = null;
		// 微信设置
		if ( isset($config['wechatConfig']) ) {
		    $wechatConfig = $config['wechatConfig'];
		}
		if ( !$wechatConfig or !$wechatConfig['appid'] or !$wechatConfig['appsecret'] ) {
			$wechatConfig = $this->config['wechatConfig'] = M("Wechat")->where('cid=%d', $this->cid)->find();
		}
		// 二维码生成设置
		isset($config['qrConfig']) and $qrConfig = $config['qrConfig'];
		if ( !$qrConfig ) {
			$siteConfig = M($this->modelName)->where('cid=%d', $this->cid)->find();
			$qrConfig = $this->config['qrConfig'] = unserialize($siteConfig['qr_config']);
		}
		$this->wechatAdvance = new WechatAdvance($wechatConfig['appid'], $wechatConfig['appsecret']);
	}
	
	/**
	 * 获得二维码原图并保存
	 * @param string $type
	 * @param array $data 二维码数据
	 * @param string $tag 所属标签 
	 */
	public function getQrcode( $type = QrCode::QR_ACTION_FOREVER, $tag = 'default' ) {
		DBRW::openAndClose(0);
		$cacheKey = $this->getCacheKey($type, $tag);
		$sceneId = $this->getSceneId( $type, $tag ); // 获得场景id
		if ( $sceneId == false ) {
		    $this->errorCode= "000";
		    return false;
		}
		
		if ( $this->enableCache ) {
		    $returnData = $this->getCacheCode($type, $tag);
		    if ( $returnData ) {
		        /* 未知原因缓存出现$returnData({"mime":"image\/jpeg","createTime":1422175652,"expireTime":0,"image":null,"url":"http:\/\/weixin.qq.com\/q\/h3WFMpnljFH1RkQ_Klnm","dataMd5":"40cd750bba9870f18aada2478b24840a","sceneId":1,"uid":29,"codeId":"1"})
		                         临时纠证代码: 纠证缓存的sceneId与实际sceneId不符的问题 */
		        if ( $returnData['sceneId'] != $sceneId ) {
		            $returnData = null; // 重新获取
		        }
		        if ( empty($returnData['codeId']) ) {
		            $returnData = null; // 重新获取
		        }
		    }
		}
		
		if ( empty($returnData) ) {
			$qtCode = $this->findQrCode($tag); // 获得表中用户已有的QrCode(由getSceneId时自动插入)
			if ( !$qtCode ) {
		        $this->errorCode= "004";
		        return false;
			}
			$accessToken = $this->wechatAdvance->getBaseAccess();
			if ( !$accessToken['access_token'] ) {
				$this->errorCode= "001";
				return false;
			}
			$ticket = $this->wechatAdvance->getQrTicket($type, $accessToken['access_token'], array(
					'action_info' => array(
						'scene' => array(
							'scene_id' => $sceneId,
						),
					),
					'action_name' => $type,
			)); // 获得Ticket
			if ( !$ticket['ticket'] ) {
			    $this->errorCode= "002";
			    return false;
			}
			$result = $this->wechatAdvance->getQrCode($ticket['ticket']); // 下载二维码
			if ( !$result['content'] ) {
		        $this->errorCode= "003";
		        return false;
			}
			$responseHeader = $result['header'];
			$returnData = array(
					'mime' => str_replace('jpg', 'jpeg', $responseHeader['content_type']),
					'createTime' => time(),
					'expireTime' => $type == QrCode::QR_ACTION_LIMIT_TIME ? 1800 : 0,
					'image' => $result['content'],
					'url' => $ticket['url'],
					'sceneId' => $sceneId,
					'uid' => $this->uid,
					'codeId' => $qtCode['id'],
			);
			M("QrCode")->where(array('id' => $qtCode['id']))->save(array(
				'url' => $ticket['url'],
			)); // 保存二维码地址
			$this->enableCache and F($cacheKey, $returnData);
			//$ticket['url'] and $returnData['isChange'] = ($qtCode['url'] != $ticket['url']); // 二维码是否已改变
		}
		DBRW::openAndClose(1);
		return $returnData;
	}
	
	/**
	 * 获得二维码画图配置的md5
	 * @return string
	 */
	public function getQrConfigMd5() {
		$qrConfig = $this->config['qrConfig'];
		ksort($qrConfig);
		$qrConfigMd5 = md5(serialize($qrConfig));
		return $qrConfigMd5;
	}
	
	/**
	 * 画二维码
	 * @param array $data 参考cacheData
	 * @return array
	 * array(
	 * 	 'content' => '二进制内容',
	 *   'mime' => '', 
	 *   'w' => 0, 
	 *   'h' => 0,
	 *   'createfun' => ''
	 * )
	 */
	public function drawQrcode() {
		$qrConfig = $this->config['qrConfig'];
		// 加载背景图
		$imgInfo = getimagesize($qrConfig['img']);
		$createDsfun = str_replace('/', 'createfrom', $imgInfo['mime']); // 创建目标图函数
		$bgImg = $createDsfun($qrConfig['img']);
		// 画字段
		foreach ( $qrConfig['fields'] as $fieldName => $fcfg ) {
			$baseConfig = self::$fieldsConfig[$fieldName]; // 字段的基础配置
			$type = $baseConfig['type'];
			if ( $fcfg['enable']*1 ) {
				$rect  = $fcfg['rect'];
				if ( $type == 0 ) {
					if ( !$fcfg['text'] ) continue;
					// 画文字
					$color = ImageColorAllocate($bgImg, 0, 0, 0);
					imagettftext($bgImg, 15, 0, $rect['x']*1, $rect['y']*1+$rect['h']*1, $color, SAE_Font_MicroHei, $fcfg['text']);
				} elseif (  $type == 1 ) {
					if ( !$fcfg['img'] ) continue;
					$fun = isset($fcfg['createFun']) ? $fcfg['createFun'] : "imagecreatefromjpeg";
					$qrcodeImg = $fun($fcfg['img']);
					// 画图片
					imagecopyresized($bgImg, $qrcodeImg, $rect['x']*1, $rect['y']*1, 0, 0, $rect['w']*1, $rect['h']*1, imagesx($qrcodeImg), imagesy($qrcodeImg));
					imagedestroy($qrcodeImg);
				}
			}
		}
		// 获得图片二进制数据
		ob_start();
		$fun = str_replace('/', '', $imgInfo['mime']);
		$fun($bgImg);
		$imgstr = ob_get_contents();
		ob_end_clean();
		imagedestroy($bgImg);
		
		return array(
			'mime' => $imgInfo['mime'],
			'w' => $imgInfo[0], 
			'h' => $imgInfo[1],
			'createfun' => $createDsfun,
			'content' => $imgstr,
			'qrConfigMd5' => $this->getQrConfigMd5(),
		);
	}
	
	/**
	 * 获得二维码的宣传图
	 * @param string $domain
	 * @param array $data
	 */
	public function findQrPromotionImages( $codeId = 0 ) {
	    DBRW::openAndClose(0);
		$qrPromotionImages = M("QrPromotionImages")->where(array('codeId' => $codeId))->find();
		DBRW::openAndClose(1);
		return $qrPromotionImages;
	}
	
	/**
	 * 保存宣传图
	 * @param unknown $data
	 */
	public function submitQrPromotionImages( $data ) {
		if ( isset($data['id']) ) {
			$fun = "save";
		} else {
			$fun = "add";
		}
		return M("QrPromotionImages")->$fun($data);
	}
	
	/**
	 * 保存宣传图片
	 * @param unknown $domain 保存域
	 * @param unknown $data 宣传图配置数据drawQrcode返回
	 */
	public function saveFile( $domain, $data ) {
		$mime = explode('/', $data['mime']);
		$s = new \SaeStorage();
		$saveName = date('YmdHis') . rand(1234, 9999) . rand(1234, 9999).".".$mime[1];
		$s->write($domain, $saveName, $data['content']);
		return $s->getUrl($domain, $saveName);
	}
	
	public function getConfig() {
		return $this->config;
	}
	
	/**
	 * 获得表中用户已有的QrCode
	 * @param string $tag
	 * @param int $uid
	 * @return unknown
	 */
	public function findQrCode( $tag = 'default', $uid = 0 ) {
	    $uid = $uid ? $uid : $this->uid;
	    DBRW::openAndClose(0);
		$qtCode = M("QrCode")->where(array('cid' => $this->cid, 'uid' => $this->uid, 'tag' => $tag,))->find();
		DBRW::openAndClose(1);
		return $qtCode;
	}
	
	/**
	 * 获得场景id(一个场景对应一个二维码)
	 * @param unknown $type 二维码类型
	 * @param string $tag 标签
	 * @return number
	 */
	public function getSceneId( $type = QrCode::QR_ACTION_FOREVER, $tag = 'default') {
		$wechatConfig = $this->config['wechatConfig'];
		DBRW::openAndClose(0);
		// 查询用户已申请到的code
		$qtCode = $this->findQrCode( $tag );
		if ( $qtCode ) {
			return $qtCode['senceId']*1;
		} else {
		    /* 场景计数 */
		    $maxindex = null;
			$condition = array('appid' => $wechatConfig['appid'], 'type' => $type);
			$qrScene = M("QrScene")->where($condition)->find();
			if ( !$qrScene ) {
				$qrScene = array(
					'appid' => $wechatConfig['appid'],
					'type' => $type,
					'max' => 0,
				);
				$qrScene['id'] = M("QrScene")->add($qrScene);
				$maxindex = 0;
			}
			/* 获得新的场景id */
			do {
				$maxindex !== 0 and $maxindex = M("QrScene")->where($condition)->max('max');
				$newIndex = $maxindex + 1;
				$s = array_merge($condition, array(
					'max' => array('eq', $maxindex)
				));
			} while( !M("QrScene")->where($s)->save(array('max' => $newIndex)) );
			/* 设置场景id到qrcode */
			M("QrCode")->add(array(
				'cid' => $this->cid,
				'uid' => $this->uid,
				'openId' => $this->openId,
				'tag' => $tag,
				'senceId' => $newIndex,
				'qrSceneId' => $qrScene['id'],
			));
			return $newIndex*1;
		}
		DBRW::openAndClose(1);
		return 0;
	}
	
	/**
	 * 获得缓存中的有效二维码
	 */
	public function getCacheCode( $type = QrCode::QR_ACTION_FOREVER, $tag = 'default' ) {
		$cacheKey = $this->getCacheKey($type, $tag);
		$cacheData = null;
		$cacheData = F($cacheKey);
		if ( $cacheData ) {
			// 验证超时
			$cacheData['expireTime'] and (time() - $cacheData['createTime'] >= $cacheData['expireTime']) and $cacheData = null;
            !$cacheData and F($cacheKey, null);
		}
		return $cacheData;
	}
	
	/**
	 * 获得缓存key
	 * @param unknown $tag
	 * @param unknown $type
	 * @return string
	 */
	public function getCacheKey( $type = QrCode::QR_ACTION_FOREVER, $tag = 'default' ) {
	    return $this->qrKeyPrefix.md5($this->cid.'_'.$this->openId.'_'.$tag.'_'.$type);
	}
	
}
